package com.example.demo.config;

import org.quartz.spi.JobFactory;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.boot.autoconfigure.quartz.QuartzDataSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;
import java.io.IOException;
import java.util.Properties;

/**
 *
 * @author Liunh
 * @date 2019/2/10
 */
@Configuration
public class QuartzConfiguration {

    @Autowired
    private AppConfig appConfig;

    @Bean
    @QuartzDataSource
    public DataSource quartzDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setUsername(appConfig.getQuartzDatasourceQuartzDataSourceUser());
        dataSource.setPassword(appConfig.getQuartzDatasourceQuartzDataSourcePassword());
        dataSource.setUrl(appConfig.getQuartzDatasourceQuartzDataSourceUrl());
        dataSource.setDriverClassName(appConfig.getQuartzDatasourceQuartzDataSourceDriver());
        return dataSource;
    }


    /*@Bean
    public PlatformTransactionManager txManager() throws PropertyVetoException {
        return new DataSourceTransactionManager(quartzDataSource());
    }*/

    @Bean
    public JobFactory jobFactory(ApplicationContext applicationContext) {
        AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
        jobFactory.setApplicationContext(applicationContext);
        return jobFactory;
    }

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) throws IOException, PropertyVetoException {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        //可选,QuartzScheduler启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录
        factory.setOverwriteExistingJobs(true);
        factory.setAutoStartup(true);
        factory.setQuartzProperties(quartzProperties());
        factory.setDataSource(quartzDataSource());
        //factory.setTransactionManager(txManager);
        //factory.setConfigLocation(new ClassPathResource("/quartz.properties"));
        factory.setJobFactory(jobFactory);
        return factory;
    }

    @Bean
    public Properties quartzProperties() throws IOException {
        Properties prop = new Properties();
        prop.put("org.quartz.scheduler.instanceName", appConfig.getQuartzSchedulerInstanceName());
        prop.put("org.quartz.scheduler.instanceId", appConfig.getQuartzSchedulerInstanceId());
        prop.put("org.quartz.scheduler.skipUpdateCheck", appConfig.getQuartzSchedulerSkipUpdateCheck());
        prop.put("org.quartz.scheduler.jobFactory.class", appConfig.getQuartzSchedulerJobFactoryClass());
        prop.put("org.quartz.jobStore.class", appConfig.getQuartzJobStoreClass());
        prop.put("org.quartz.jobStore.driverDelegateClass", appConfig.getQuartzJobStoreDriverDelegateClass());
        prop.put("org.quartz.jobStore.tablePrefix", appConfig.getQuartzJobStoreTablePrefix());
        prop.put("org.quartz.jobStore.isClustered", appConfig.getQuartzJobStoreIsClustered());
        prop.put("org.quartz.threadPool.class", appConfig.getQuartzThreadPoolClass());
        prop.put("org.quartz.threadPool.threadCount", appConfig.getQuartzThreadPoolThreadCount());
        prop.put("org.quartz.jobStore.dataSource", appConfig.getQuartzJobStoreDatasource());
        prop.put("org.quartz.dataSource.quartzDataSource.connectionProvider.class", appConfig.getQuartzDatasourceQuartzDataSourceConnectionProviderClass());
        prop.put("org.quartz.dataSource.quartzDataSource.driver", appConfig.getQuartzDatasourceQuartzDataSourceDriver());
        prop.put("org.quartz.dataSource.quartzDataSource.url", appConfig.getQuartzDatasourceQuartzDataSourceUrl());
        prop.put("org.quartz.dataSource.quartzDataSource.username", appConfig.getQuartzDatasourceQuartzDataSourceUser());
        prop.put("org.quartz.dataSource.quartzDataSource.password", appConfig.getQuartzDatasourceQuartzDataSourcePassword());
        prop.put("org.quartz.dataSource.quartzDataSource.maxConnections", appConfig.getQuartzDatasourceQuartzDataSourceMaxConnections());
        return prop;
    }

    public static class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {

        private transient AutowireCapableBeanFactory beanFactory;

        @Override
        public void setApplicationContext(final ApplicationContext context) {
            beanFactory = context.getAutowireCapableBeanFactory();
        }

        @Override
        protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
            final Object job = super.createJobInstance(bundle);
            beanFactory.autowireBean(job);
            return job;
        }
    }

}
